#include<stdio.h>
#include "syntax_tree.h"
#include "interpreter.h"
#include "tiny_y.h"
#include <malloc.h>
//static itpt_ret* id_func(syntax_t t,symbol_table st)
#define Length(list) (sizeof(list)/sizeof(list[0]))
extern symbol_table st;
static itpt_ret* id_func(syntax_t t)
{
	itpt_ret* ret;
	char *name=NULL;
	symbol *sb;
	if (t->type!=SYN_ID)
		{
			return NULL;
		}
	name=t->id.name;
	if((sb=symbol_table_get(st,name))==NULL){
		if((sb=symbol_create(name,SYMBOL_INT))==NULL){
			return NULL;
		}
		symbol_table_add(st,sb);
	}
	ret=itpt_ret_creat(ITPT_VAR);
	ret->var=sb;
	return ret;
}
//must write a free func for id_func()
static itpt_ret* const_func(syntax_t t){
	itpt_ret* ret;
	if (t->type!=SYN_CONST)
		{
			return NULL;
		}
	ret=itpt_ret_creat(ITPT_INT);
	ret->integer=t->con.value;
	return ret;
}
void int_print(itpt_ret * ret)
{
	printf ("%d\n", ret->integer);
}
void var_print(itpt_ret * ret)
{

	printf("%s=%d\n",ret->var->name,*(int*)ret->var->content);

}
struct{
	itpt_ret_type type;
	void (*func)(itpt_ret*);
}print_func_list[]={
	{ITPT_INT,int_print},
	{ITPT_VAR,var_print},
};
static itpt_ret* op_print_func(syntax_t t)
{
	int i=0;
	int length=Length(print_func_list);
	itpt_ret *ret=interpreter(t->op.children[0]);
	if (ret==NULL)
		{
			return NULL;
		}
	for(i=0;i<length;++i){
		if (ret->type==print_func_list[i].type)
			{
				print_func_list[i].func(ret);
			}
	}
	itpt_ret_free(ret);
	return NULL;
}

static itpt_ret* op_if_func(syntax_t t)
{
	/*	if(t->op.type!='+')
		return 0;           */
	itpt_ret * condition_ret;
	int condition=isTrue((condition_ret=interpreter(t->op.children[0])));
	itpt_ret_free(condition_ret);
	
	if (t->op.chno==2)
		{
			if (condition)
				{
					return interpreter(t->op.children[1]);
				}
			return NULL;
		}
	else if (t->op.chno==3)
		{
			if (condition)
				{
					return interpreter(t->op.children[1]);
				}
			else
				return interpreter(t->op.children[2]);
		}
	else{
		printf ("op if must has 2 or 3 parameters\n");
		return NULL;
	}
}
static itpt_ret* op_add_func(syntax_t t)
{
	itpt_ret *ret;
	itpt_ret ** params;
	int params_no=t->op.chno;
	if (params_no!=2)
		{
			printf("op + must has two parameters\n");
			return NULL;
		}
	if((params=get_itpt_ret_list(t->op.children,params_no))==NULL)
		return NULL;
	if(t->op.type!='+'){
		free_itpt_ret_list(params,params_no);
		return NULL;
	}
	if((ret=itpt_ret_creat(ITPT_INT))==NULL){
		free_itpt_ret_list(params,params_no);
		return NULL;
	}
	ret->integer=params[0]->integer+params[1]->integer;
	free_itpt_ret_list(params,params_no);
	return ret;
}
static itpt_ret* op_sub_func(syntax_t t)
{
	itpt_ret *ret;
	itpt_ret ** params;
	int params_no=t->op.chno;
	if (params_no!=2)
		{
			printf("op - must has two parameters\n");
			return NULL;
		}
	if((params=get_itpt_ret_list(t->op.children,params_no))==NULL)
		return NULL;
	if(t->op.type!='-'){
		free_itpt_ret_list(params,params_no);
		return NULL;
	}
	if((ret=itpt_ret_creat(ITPT_INT))==NULL){
		free_itpt_ret_list(params,params_no);
		return NULL;
	}
	ret->integer=params[0]->integer-params[1]->integer;
	free_itpt_ret_list(params,params_no);
	return ret;
}
static itpt_ret* op_mul_func(syntax_t t)
{
	itpt_ret *ret;
	itpt_ret ** params;
	int params_no=t->op.chno;
	if (params_no!=2)
		{
			printf("op * must has two parameters\n");
			return NULL;
		}
	if((params=get_itpt_ret_list(t->op.children,params_no))==NULL)
		return NULL;
	if(t->op.type!='*'){
		free_itpt_ret_list(params,params_no);
		return NULL;
	}
	if((ret=itpt_ret_creat(ITPT_INT))==NULL){
		free_itpt_ret_list(params,params_no);
		return NULL;
	}
	ret->integer=params[0]->integer*params[1]->integer;
	free_itpt_ret_list(params,params_no);
	return ret;
}
static itpt_ret* op_div_func(syntax_t t)
{
	itpt_ret *ret;
	itpt_ret ** params;
	int params_no=t->op.chno;
	int div;
	if (params_no!=2)
		{
			printf("op / must has two parameters\n");
			return NULL;
		}
	if((params=get_itpt_ret_list(t->op.children,params_no))==NULL)
		return NULL;
	if(t->op.type!='/'){
		free_itpt_ret_list(params,params_no);
		return NULL;
	}
	if((ret=itpt_ret_creat(ITPT_INT))==NULL){
		free_itpt_ret_list(params,params_no);
		return NULL;
	}
	if((div=params[1]->integer)==0){
		printf ("div number must not be 0\n");
		free_itpt_ret_list(params,params_no);
		return NULL;
	}
	ret->integer=params[0]->integer/div;
	free_itpt_ret_list(params,params_no);
	return ret;
}
itpt_ret* op_assign_func(syntax_t t)
{
	itpt_ret *ret;
	itpt_ret ** params;
	int params_no=t->op.chno;
	if (params_no!=2)
		{
			printf("op = must has two parameters\n");
			return NULL;
		}
	if((params=get_itpt_ret_list(t->op.children,params_no))==NULL)
		return NULL;
	if(t->op.type!='='){
		free_itpt_ret_list(params,params_no);
		return NULL;
	}
	if((ret=itpt_ret_creat(ITPT_INT))==NULL){
		free_itpt_ret_list(params,params_no);
		return NULL;
	}
	ret->var=params[0]->var;
	*((int*)(ret->var->content))=params[1]->integer;
	return ret;
}
itpt_ret* op_sem_func(syntax_t t)
{
	itpt_ret *temp;
	int params_no=t->op.chno;
	if (params_no!=2)
		{
			printf("op = must has two parameters\n");
			return NULL;
		}
	if(t->op.type!=';'){
		return NULL;
	}
	if(temp=interpreter(t->op.children[0]))
		itpt_ret_free(temp);
	if(temp=interpreter(t->op.children[1]))
		itpt_ret_free(temp);
	return NULL;
}
struct 
{
    int type;
	itpt_ret* (*func)(syntax_t);
}op_func_list[]={
	{'+',op_add_func},
	{'-',op_sub_func},
	{'*',op_mul_func},
	{'/',op_div_func},
	{IF,op_if_func},
	{'=',op_assign_func},
    {';',op_sem_func},
	{PRINT,op_print_func},
};
static itpt_ret* op_func(syntax_t t){
	int i=0;
	int length=Length(op_func_list);
	if(t->type!=SYN_OP)
		return 0;
	for (i = 0; i <length; ++i)
		{
			if (t->op.type==op_func_list[i].type)
				{
					return op_func_list[i].func(t);
				}
		}
	return 0;
}

struct 
{
	SYN_TYPE type;
	itpt_ret* (*func)(syntax_t);
}syn_func_list[]={
	{SYN_CONST,const_func},
	{SYN_OP,op_func},
	{SYN_ID,id_func},
};

itpt_ret* itpt_ret_creat(itpt_ret_type type)
{
	itpt_ret* ret=malloc(sizeof(itpt_ret));
	ret->type=type;
	return ret;
}
void itpt_ret_free(itpt_ret* e)
{
	free(e);
}
// the list must not contain NULL
/*
  //do like this will due to memory leak
itpt_ret** get_itpt_ret_list(syntax_t * stlist,int no)
{
	int i;
	itpt_ret** list=(itpt_ret**)malloc((itpt_ret*)*no);
	for (i=0; i < no; ++i)
		{
			if((list[i]=interpreter(stlist[i]))==NULL)
				break;
		}
	if(i==no)
		return list;
	for (--i; i>=0; --i)
			itpt_ret_free(list[i]);
	free(list);
	return NULL;
}
*/
//of course, the list must not contain NULL
itpt_ret** get_itpt_ret_list(syntax_t * stlist,int no)
{
	int i;
	int state=0;
	itpt_ret** list=(itpt_ret**)malloc(sizeof(itpt_ret*)*no);
	if(list==NULL){
		printf ("out of memory\n");
		return NULL;
	}
	for (i=0; i < no; ++i)
		{
			if((list[i]=interpreter(stlist[i]))==NULL)
				state=1;
		}
	if(!state)
		return list;

	for (i=0; i < no; ++i)
		{
			if(list[i])
				itpt_ret_free(list[i]);
		}

	free(list);
	return NULL;
}

void free_itpt_ret_list(itpt_ret** list,int no)
{
	int i;
	for (i = 0; i < no; ++i)
		{
			itpt_ret_free(list[i]);
		}
	free(list);
}
int int_isTrue(itpt_ret * ret)
{
	if(ret==NULL)
		return 0;
	return ret->integer;
}
int var_isTure(itpt_ret * ret)
{
	if(ret==NULL)
		{return 0;}
	return *(int*)ret->var->content;
}
struct{
	itpt_ret_type type;
	int (*func)(itpt_ret*);
}isTrue_func_list[]={
	{ITPT_INT,int_isTrue},
	{ITPT_VAR,var_isTure},
};
int isTrue(itpt_ret *ret)
{
	int i=0;
	int length=Length(isTrue_func_list);
	//printf ("length=%d\n",length);
	if (ret==NULL)
		{
			return 0;
		}
	for(i=0;i<length;++i){
		if (ret->type==isTrue_func_list[i].type)
			{
				return isTrue_func_list[i].func(ret);
			}
	}
	return 0;
}

itpt_ret* interpreter(syntax_t t)
{
	int i;
	int length=Length(syn_func_list);
	if(t==NULL)
		return NULL;
	for (i = 0; i < length; ++i)
		{
			if(syn_func_list[i].type==t->type)
				return syn_func_list[i].func(t);
		}
	return NULL;
}
